<?php

/**
 * 
 */
interface IValidationAttribute
{
    /**
     * 
     */
    function isValid($value);

    /**
     *
     */
    function getErrorMessage();
}

/**
 * 
 */
class RequiredAttribute implements IValidationAttribute
{
    /**
     *
     * @param mixed $value
     * @return boolean
     */
    public function isValid($value)
    {
        return strlen($value) !== 0;
    }

    /**
     *
     * @return string
     */
    public function getErrorMessage()
    {
        return "The field '%s' is required.";
    }
}

/**
 * 
 */
class NumericAttribute implements IValidationAttribute
{
    /**
     *
     * @param mixed $value
     * @return boolean
     */
    public function isValid($value)
    {
        return (!is_numeric($value) || !preg_match('/^[0-9, ]+$/', $value));
    }

    /**
     *
     * @return string
     */
    public function getErrorMessage()
    {
        return "The field '%s' must be a number.";
    }
}

class StringLengthAttribute implements IValidationAttribute
{
    /**
     *
     * @var integer
     */
    private $minLength;

    /**
     *
     * @var integer
     */
    private $maxLength;

    /**
     *
     * @param integer $minLength
     * @param integer $maxLength
     */
    public function __construct($minLength, $maxLength = null)
    {
        $this->minLength = (int) $minLength;
        $this->maxLength = (int) $maxLength;
    }

    /**
     *
     * @param mixed $value
     * @return boolean
     */
    public function isValid($value)
    {
        $valueLength = strlen((string) $value);
        if ($this->maxLength === null) {
            return ($valueLength >= $this->minLength);
        }
        return ($valueLength >= $this->minLength && $valueLength <= $this->maxLength);
    }

    /**
     *
     * @return string
     */
    public function getErrorMessage()
    {
        if ($this->maxLength === null) {
            return "The field '%s' must be at least {$this->minLength} characters long.";
        }
        return "The field '%s' must be between {$this->minLength} and {$this->maxLength} characters long.";
    }
}
